import * as PIXI from "pixi.js";

export default function () {
  let app;
  const pixiTool = {
    lineList: [],
    highlightPoint: null,
    lineSingleSize: 5, //  单向线宽度
    lineDoubleSize: 5, //  双向线宽度
    lineSingleColor: "0x1B9AF7", //  单向线颜色
    lineDoubleColor: "0x1B9AF7", //  双向线颜色
    lineSingleAlpha: 0.25, //  单向线透明度
    lineDoubleAlpha: 1, //  双向线透明度
    clickPoint: (p) => {
      console.log(p.id);
    },
    isOnCanvas: (bool) => {
      console.log("is on canvas:" + bool);
    },
  };

  let dragTarget, startPointX, startPointY;

  /**
   * 创建舞台
   * @param div canvas的父类div
   * @returns {PIXI.Container|number|null|*} pixijs的舞台元素，即根级父类容器
   */
  pixiTool.createStage = (div) => {
    if (!div) return null;
    const width = div.offsetWidth;
    const height = div.offsetHeight;
    app = new PIXI.Application({
      width,
      height,
      antialias: true,
      resizeTo: div,
      backgroundColor: "#FFFFFF",
    });
    div.appendChild(app.view);
    pixiTool.initStage();
    return app.stage;
  };

  /**
   * 销毁舞台
   */
  pixiTool.destroyStage = () => {
    app.stage.children.forEach((item) => {
      if (item.isSprite) {
        item.destroy();
      } else {
        item.destroy(true);
      }
    });
    app.destroy(true, true);
  };

  /**
   * 初始化所有对象
   */
  pixiTool.initStage = () => {
    if (!pixiTool.div) return;
    pixiTool.bg = new PIXI.TilingSprite(); //  背景
    pixiTool.areaContainer = new PIXI.Container(); //  区域的容器
    pixiTool.lineContainer = new PIXI.Container(); //  存放线的容器
    pixiTool.pointContainer = new PIXI.Container(); //  存放点的容器
  };

  /**
   * 展示舞台内所有元素
   */
  pixiTool.updateStage = () => {
    if (!pixiTool.div) return;
    pixiTool.stage.addChild(pixiTool.bg);
    pixiTool.stage.addChild(pixiTool.areaContainer);
    pixiTool.stage.addChild(pixiTool.lineContainer);
    pixiTool.stage.addChild(pixiTool.pointContainer);
    app.stage.eventMode = "static";
    app.stage.onpointerdown = wholeStart;
    app.stage.onpointerup = wholeEnd;
    app.stage.onpointerupoutside = wholeEnd;
  };

  function wholeStart(e) {
    startPointX = pixiTool.stage.x - e.global.x;
    startPointY = pixiTool.stage.y - e.global.y;
    dragTarget = pixiTool.stage;
    app.stage.onpointermove = wholeMove;
  }
  function wholeMove(e) {
    if (dragTarget) {
      dragTarget.x =
        e.global.x + startPointX > 0
          ? 0
          : e.global.x + startPointX < pixiTool.div.offsetWidth - 4000
          ? pixiTool.div.offsetWidth - 4000
          : e.global.x + startPointX;
      dragTarget.y =
        e.global.y + startPointY > 0
          ? 0
          : e.global.y + startPointY < pixiTool.div.offsetHeight - 4000
          ? pixiTool.div.offsetHeight - 4000
          : e.global.y + startPointY;
      // 固定红线区域位置
      pixiTool.areaContainer.x = -dragTarget.x;
      pixiTool.areaContainer.y = -dragTarget.y;
      if (pixiTool.highlightPoint) {
        const p = pixiTool.savedList.find(
          (item) => item.id === pixiTool.highlightPoint.id
        );
        if (p && !p.onCanvas) {
          // 判断点是否进入画布，否则不随画布移动
          pixiTool.pointContainer.getChildByName(pixiTool.highlightPoint.id).x =
            p.canvasX - dragTarget.x;
          pixiTool.pointContainer.getChildByName(pixiTool.highlightPoint.id).y =
            p.canvasY - dragTarget.y;
        }
      }
    }
  }
  function wholeEnd() {
    if (dragTarget) {
      app.stage.onpointermove = null;
      dragTarget = null;
    }
    if (pixiTool.highlightPoint) {
      const index = pixiTool.savedList.findIndex(
        (item) => item.id === pixiTool.highlightPoint.id
      );
      if (index >= 0) {
        const pos = pixiTool.savedList[index];
        // 是否满足移除条件
        if (
          pos.onCanvas &&
          pos.canvasX + pixiTool.stage.x < 130 &&
          pos.canvasY + pixiTool.stage.y < 130
        )
          removePoint(pos.id);
        // 是否满足加入画布条件
        if (
          !pos.onCanvas &&
          (pos.canvasX + pixiTool.stage.x > 130 ||
            pos.canvasY + pixiTool.stage.y > 130)
        ) {
          pos.onCanvas = true;
          pixiTool.isOnCanvas(true);
        }
        pixiTool.areaContainer.getChildByName("bin").visible = false;
      }
    }
  }

  /**
   * 创建背景
   * @param options ：
   *    * img - 背景图片
   *    * width - 背景宽度
   *    * height - 背景高度
   * @returns {*} 地图对象，pixijs的精灵
   * @constructor
   */
  pixiTool.createBg = (options) => {
    if (!options.img) return null;
    const img = PIXI.Texture.from(options.img);
    const width = options.width || 4000;
    const height = options.height || 4000;
    pixiTool.bg = new PIXI.TilingSprite(img, width, height);
    pixiTool.bg.alpha = 0.15;
    return pixiTool.bg;
  };

  // 创建区域
  pixiTool.createArea = () => {
    const leftX = new PIXI.Graphics();
    const leftY = new PIXI.Graphics();
    leftX.clear();
    leftX.lineStyle(5, "0xFF0000");
    leftX.moveTo(0, 130);
    leftX.lineTo(130, 130);
    leftY.clear();
    leftY.lineStyle(5, "0xFF0000");
    leftY.moveTo(130, 0);
    leftY.lineTo(130, 130);
    pixiTool.areaContainer.addChild(leftX);
    pixiTool.areaContainer.addChild(leftY);
    const bin = PIXI.Sprite.from("posture/bin.png");
    bin.tint = "0xFF0000";
    bin.scale.set(0.4);
    bin.anchor.set(0.5);
    bin.x = 65;
    bin.y = 65;
    bin.name = "bin";
    bin.visible = false;
    pixiTool.areaContainer.addChild(bin);
  };

  // 创建连线
  pixiTool.drawRail = (list, needClone = false) => {
    if (list)
      pixiTool.savedList = needClone ? JSON.parse(JSON.stringify(list)) : list;
    if (!pixiTool.savedList) return;
    pixiTool.clearRail();
    const m = new Map();
    pixiTool.savedList.forEach((v, n) => {
      v.index = n;
      m.set(v.id, v);
    });
    pixiTool.savedList.forEach((item, index) => {
      pixiTool.pointContainer.addChild(createPoint(item));
      if (pixiTool.highlightPoint && pixiTool.highlightPoint.id === item.id)
        pixiTool.highlight(item);
      item.connected = item.connected || [];
      item.connected.forEach((p) => {
        if (!m.get(p)) return; // 连接点中的跨地图点直接return，不进行连线
        //  将两个点的下标组合成ID，如点3和点4的连接，3-4
        const lineId = index + "-" + m.get(p).index;
        //  查找是否已存在连线，用反向ID去查询，如4-3
        const antherLine = pixiTool.getLine(m.get(p).index + "-" + index);
        if (antherLine) {
          //  查到已存在一条连接线，进行编辑，若未查询到，则进行创建
          pixiTool.editLine(
            antherLine,
            { x: item.canvasX, y: item.canvasY },
            { x: m.get(p).canvasX, y: m.get(p).canvasY },
            true
          );
        } else {
          const line = createLine(
            { x: item.canvasX, y: item.canvasY },
            { x: m.get(p).canvasX, y: m.get(p).canvasY }
          );
          line.name = lineId;
          // 把线名存起来
          pixiTool.lineList.push({ start: index, end: m.get(p).index });
          pixiTool.lineContainer.addChild(line);
        }
      });
    });
  };

  // 清空连线
  pixiTool.clearRail = () => {
    pixiTool.pointContainer.removeChildren();
    pixiTool.lineContainer.removeChildren();
    pixiTool.lineList = [];
  };

  // 创建点位
  function createPoint(p) {
    const pos = p.pose || p;
    // 点对象
    const point = new PIXI.Container();
    //  点素材
    const pose = new PIXI.Graphics();
    //  点名称
    const pointText = new PIXI.Text(pos.name);
    point.addChild(pose);
    point.addChild(pointText);
    // 点素材参数
    normalPoint(pose, p);
    //  点名称参数
    pointText.anchor.set(0.5);
    pointText.y = -40;
    //  点位整体参数
    point.x = pos.onCanvas ? pos.canvasX : (pos.canvasX = 65);
    point.y = pos.onCanvas ? pos.canvasY : (pos.canvasY = 80);
    point.name = pos.id;
    point.visible = pos.onCanvas;
    // -----------事件分割线-------------
    pose.eventMode = "static";
    pose.onpointerdown = (e) => {
      e.stopPropagation();
      if (pos.onCanvas)
        pixiTool.areaContainer.getChildByName("bin").visible = true;
      pixiTool.clickPoint(pos);
      dragTarget = point;
      app.stage.onpointermove = poseMove;
    };
    function poseMove(e) {
      if (dragTarget) {
        // 获取元素坐标
        dragTarget.parent.toLocal(e.global, null, dragTarget.position);
        pos.canvasX = dragTarget.x;
        pos.canvasY = dragTarget.y;
        // 获取当前点的下标
        const index = pixiTool.savedList.indexOf(pos);
        // 如果当前点有连线
        if (index >= 0 && pixiTool.savedList[index].connected.length) {
          // 遍历连线的缓存list
          pixiTool.lineList.forEach((item) => {
            // 如果当前点为某条线的起点，编辑线，起点坐标为拖动的坐标，终点为原来的终点
            if (item.start === index) {
              const startPos = { x: dragTarget.x, y: dragTarget.y };
              const endPos = {
                x: pixiTool.savedList[item.end].canvasX,
                y: pixiTool.savedList[item.end].canvasY,
              };
              pixiTool.editLine(
                pixiTool.getLine(item.start + "-" + item.end),
                startPos,
                endPos
              );
            }
            // 如果当前点为某条线的终点，编辑线，起点坐标为原来的起点，终点为拖动的坐标
            if (item.end === index) {
              const startPos = {
                x: pixiTool.savedList[item.start].canvasX,
                y: pixiTool.savedList[item.start].canvasY,
              };
              const endPos = { x: dragTarget.x, y: dragTarget.y };
              pixiTool.editLine(
                pixiTool.getLine(item.start + "-" + item.end),
                startPos,
                endPos
              );
            }
          });
        }
      }
    }
    return point;
  }

  pixiTool.highlight = (p) => {
    if (pixiTool.highlightPoint) {
      // 判断是否已有高亮点
      if (pixiTool.highlightPoint === p) {
        // 如果两次高亮为同一个点，则进行对焦
        // pixiTool.lookAt(p)
      } else {
        const oldPoint = pixiTool.pointContainer.getChildByName(
          pixiTool.highlightPoint.id
        );
        if (oldPoint) {
          // 把之前的高亮点取消
          normalPoint(oldPoint.getChildAt(0), pixiTool.highlightPoint);
          const oldP = pixiTool.savedList.find(
            (item) => item.id === oldPoint.name
          );
          if (oldP && !oldP.onCanvas) {
            // 判断老点是否进入画布，否则隐藏
            oldPoint.visible = false;
          }
        }
      }
    }
    pixiTool.highlightPoint = pixiTool.savedList.find(
      (item) => item.id === p.id
    );
    const point = pixiTool.pointContainer.getChildByName(p.id);
    if (point) {
      if (!point.visible) {
        point.x = 65 - pixiTool.stage.x;
        point.y = 80 - pixiTool.stage.y;
        point.visible = true;
      }
      lightPoint(point.getChildAt(0), pixiTool.highlightPoint);
    }
  };

  function lightPoint(pose, data) {
    pose.clear();
    pose.lineStyle(4, "0xFF0000");
    if (data && data.start) {
      pose.beginFill("0xFF8C00", 1);
    } else {
      pose.beginFill("0x9370DB", 1);
    }
    pose.drawCircle(0, 0, 25);
    pose.endFill();
  }

  function normalPoint(pose, data) {
    pose.clear();
    if (data && data.start) {
      pose.beginFill("0xFF8C00", 0.5);
    } else {
      pose.beginFill("0x9370DB", 0.5);
    }
    pose.drawCircle(0, 0, 25);
    pose.endFill();
  }

  // 移除点位
  function removePoint(id) {
    pixiTool.isOnCanvas(false);
    const pose = pixiTool.savedList.find((item) => item.id === id);
    if (pose) {
      // 重置点位数据
      pose.onCanvas = false;
      pose.canvasX = 65;
      pose.canvasY = 80;
    }
    const point = pixiTool.pointContainer.getChildByName(id);
    if (point) point.visible = false;
    pixiTool.highlightPoint = null;
  }

  /**
   * 创建线
   * @param startPoint 起点坐标
   * @param endPoint 终点坐标
   * @returns {PIXI.Graphics} 线对象（pixijs的精灵）
   */
  function createLine(startPoint, endPoint) {
    const line = new PIXI.Graphics();
    return pixiTool.editLine(line, startPoint, endPoint);
  }

  /**
   * 获取线对象
   * @param id 线对象id
   */
  pixiTool.getLine = (id) => {
    return pixiTool.lineContainer.getChildByName(id);
  };

  /**
   * 编辑线
   * @param line 线对象
   * @param startPoint 起点坐标
   * @param endPoint 终点坐标
   * @param isDouble  是否双向
   */
  pixiTool.editLine = (line, startPoint, endPoint, isDouble = true) => {
    line.clear();
    if (isDouble) {
      //  判断是否是双向线
      line.lineStyle(
        pixiTool.lineDoubleSize,
        pixiTool.lineDoubleColor,
        pixiTool.lineDoubleAlpha
      );
    } else {
      line.lineStyle(
        pixiTool.lineSingleSize,
        pixiTool.lineSingleColor,
        pixiTool.lineSingleAlpha
      );
    }
    line.moveTo(startPoint.x, startPoint.y);
    line.lineTo(endPoint.x, endPoint.y);
    return line;
  };

  /**
   * 对焦
   * @param pos 焦点点位
   */
  pixiTool.lookAt = (pos) => {
    // 判断新的点位不进行对焦
    if (pos.canvasX === 65 && pos.canvasY === 80) return;
    pixiTool.stage.x = pixiTool.div.offsetWidth / 2;
    pixiTool.stage.y = pixiTool.div.offsetWidth / 2;
    app.stage.x -= pos.canvasX * app.stage.scale.x;
    app.stage.y -= pos.canvasY * app.stage.scale.y;
    pixiTool.areaContainer.x = -app.stage.x;
    pixiTool.areaContainer.y = -app.stage.y;
  };

  return pixiTool;
}
